$extend(String, {
  interpret: function(value) {
    return value == null ? '' : String(value);
  }
});

$extend(String.prototype, {
	gsub : function(pattern, replacement) {
		var result = '', source = this, match;
		replacement = arguments.callee.prepareReplacement(replacement);
		while (source.length > 0) {
			if (match = source.match(pattern)) {
				result += source.slice(0, match.index);
				result += replacement(match).toString();
				source  = source.slice(match.index + match[0].length);
			} else {
				result += source, source = '';
			}
		}
		return result;
	},
	
	startsWith: function(pattern) {
		return this.indexOf(pattern) === 0;
	},
	
	escapeHTML: function() {  
		if (!this.length) return '';  
		var htmlString = '';  
		for (var i=0; i<this.length; i++) {  
			switch (this.substr(i,1))	{  
				case	'&'	: htmlString += "&amp;";			break;  
				case	'<'	: htmlString += "&lt;";				break;  
				case	'>'	: htmlString += "&gt;";				break;  
				case	' '	: htmlString += "&nbsp;";			break;  
				case	'"'	: htmlString += "&quot;";			break;  
				default	: htmlString += this.substr(i,1);	break;  
			}  
		}  
		return htmlString;  
	}
});

String.prototype.gsub.prepareReplacement = function(replacement) {
  if ($type(replacement) == 'function') return replacement;
  var template = new Template(replacement);
  return function(match) { return template.evaluate(match) };
};

var Template = new Class({
	initialize: function(template, pattern) {
		this.template = template.toString();
		this.pattern = pattern || Template.Pattern;
	},

	evaluate: function(object) {
		if ($type(object.toTemplateReplacements) == 'function')
			object = object.toTemplateReplacements();

		return this.template.gsub(this.pattern, function(match) {
			if (object == null) return '';

			var before = match[1] || '';
			if (before == '\\') return match[2];

			var ctx = object, expr = match[3];
			var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/, match = pattern.exec(expr);
			if (match == null) return before;

			while (match != null) {
				var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
				ctx = ctx[comp];
				if (null == ctx || '' == match[3]) break;
				Expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
				match = pattern.exec(expr);
			}

			return before + String.interpret(ctx);
		}.bind(this));
	},
	
	evaluateHTML: function(object) {
		if ($type(object.toTemplateReplacements) == 'function')
			object = object.toTemplateReplacements();
		var newObject ={};
		for (var prop in object) {
			newObject[prop] = object[prop].escapeHTML();
		}
		return this.evaluate(newObject);
	}
});
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; 

/* mootools 1.2b1 不需要这个扩展
Hash.prototype.toQueryString = function(){
	var queryString = [];
	this.each(function(value,name){
		var qs = function(val){
			queryString.push(name + '=' + encodeURIComponent(val));
		};
		if ($type(value) == 'array') value.each(qs);
		else qs(value);
	});
	return queryString.join('&');
}
*/
//fix Bug
$$.unique = function(array){
	var elements = [];
 
	for (var i = 0, l = array.length; i < l; i++){
		if (array[i].$included) continue;
		var element = $(array[i]);
 
		if (element && !element.$included){
 
			element.$included = true;
			elements.push(element);
		}
	}
 
	for (var n = 0, d = elements.length; n < d; n++) {
        	//new for IE 6 and IE 7
	  	if(window.ie) elements[n].removeAttribute('$included');
	  	else elements[n].$included=false;
 
	 }
 
	return new Elements(elements);
};

/**
 * LabelInput扩展
 * @author SouL
 * Example:
 * --------------
	var baseProps  = {'id': 'test1', 'defaultText': '默认值'};
	var inputProps = {'class': 'labelInput'};
	var test1 = new PlaceEditor(baseProps, inputProps);
	test1.build().inject('testArea');
 * --------------
 */

var PlaceEditor = new Class({
	initialize: function(baseProps, inputProps, valueBoxProps){
		this.baseProps = baseProps || {};
		this.inputProps = inputProps || {};
		this.inputProps.type = this.inputProps.type || 'text';
		this.defaultText = this.baseProps.defaultText || '';
		delete this.baseProps.defaultText;
		this.valueBoxProps = valueBoxProps || {};
		if (this.baseProps.id) {
			this.valueBoxProps.id = this.baseProps.id;
			delete this.baseProps.id;
		}
	},
	
	build: function(){
		this.base = new Element('label', this.baseProps);
		this.base.addEvent('click', this.changeToInput.bind(this));
		this.base.setValue = this.setValue.bind(this);
		this.base.setValue(this.defaultText);
		return this.base;
	},
	
	setValue: function(string){
		this.value = string;
		this.base.setText(string);
		new Element('input', this.valueBoxProps)
		.setProperty('type', 'hidden')
		.injectInside(this.base)
		.value = string;
		return this.base;
	},
	
	changeToInput: function(e){
		e = new Event(e).stop();
		callEl = e.target;
		callEl.setStyle('display', 'none');
		this.inputBox = new Element('input', this.inputProps)
		.injectAfter(callEl);
		this.inputBox.value = this.value;
		this.inputBox.focus();
		this.inputBox.addEvent('keydown', function(e){
			e = new Event(e);
			switch (e.key) {
				case 'enter' :
					e.stop();
					this.update();
					return;
					
				case 'esc' :
					e.stop();
					this.cancel();
					return;
			}
		}.bind(this));
		this.inputBox.addEvent('blur', function(e){
			e = new Event(e);
			this.update();
		}.bind(this));
	},
	
	update: function(valueString){
		this.setValue(valueString || ( this.inputBox ? (this.inputBox.value || this.defaultText) : this.defaultText));
		if (this.inputBox) this.inputBox.remove();
		this.base.setStyle('display', '');
	},
	
	cancel: function(){
		if (this.inputBox) this.inputBox.remove();
		this.base.setStyle('display', '');	
	}
});

/**
 * 生成一个数值序列（数组）
 */
var Range = function(start, stop, step){
	var result = [];
	for (var i=start; i<=stop; i+=step) {
		result.push(i)
	}
	return result;
}

/**
 * Element元素方法扩展
 */
Element.extend({
	disableSelectText : function(){
		this.addEvent('selectstart',function(e){new Event(e).stop();})
		return this;
	}
});

/**
 * 清除Object中内容为空的元素
 */
removeEmpty = function(obj){
	for(var name in obj) {
		if (!obj[name]) delete obj[name];
	}
	return obj;
};